#include "stdinc.h"
#include <Ogre.h>
#include "CopyRenderer.h"
#include "DwarfFort/Interface.h"
#include "Main/Logger.h"
#include "DwarfFort/StateMirror.h"

using namespace Graphics;


CopyRenderer::CopyRenderer(Ogre::RenderWindow *window, Ogre::uint8 id)
:mRenderWindow(window),queue_id(id), mRenderTex(0)
{
}

CopyRenderer::~CopyRenderer(void)
{
}


void CopyRenderer::renderQueueStarted(Ogre::uint8 id, const Ogre::String& invocation, bool& skipThisQueue)
{
	if (this->queue_id == id)
	{
		this->renderScreen();
	}
}
void CopyRenderer::renderQueueEnded(Ogre::uint8 id, const Ogre::String& invocation, bool& repeatThisQueue)
{
}


void CopyRenderer::renderScreen()
{
//	prepRenderBuffer();
	AsmCall custRender = DwarfFort::Interface::getSingleton().getStateMirror()->getTopState()->getVFunc(4);
	custRender();
	fillRenderBuffer(); 
	initRenderStates();
	Ogre::RenderSystem * renderSys = Ogre::Root::getSingleton().getRenderSystem();
	renderSys->_render(mRenderOp);
	//renderSys->detachRenderTarget(mRenderTex->getName());
	//renderSys->attachRenderTarget(*mRenderWindow);
//	destroyRenderBuffer();

}



void CopyRenderer::prepRenderBuffer()
{
	static const size_t vertex_count = 
								2*		// background + foreground
								25*80 *	// width * height
								2 *		// two triangles per quad
								3;		// three vertices per triangle

	using namespace Ogre;
	mRenderOp.vertexData = new VertexData;
	mRenderOp.vertexData->vertexCount = vertex_count;
	VertexDeclaration* vd = mRenderOp.vertexData->vertexDeclaration;
	size_t vd_offset = 0;
	vd->addElement(0, vd_offset, VET_FLOAT3, VES_POSITION);
	vd_offset += VertexElement::getTypeSize(VET_FLOAT3);
	vd->addElement(0, vd_offset, VET_COLOUR, VES_DIFFUSE);
	vd_offset += VertexElement::getTypeSize(VET_COLOUR);
	vd->addElement(0, vd_offset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
	
	
	mVBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(vd->getVertexSize(0), vertex_count,  
        HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false);

	mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mVBuffer);

	// complete render operation basic initialisation
	mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST;
	mRenderOp.useIndexes = false;
}

void CopyRenderer::destroyRenderBuffer()
{
	delete mRenderOp.vertexData;
    mRenderOp.vertexData = 0;
    mVBuffer.setNull();

}
	struct PCTVertex {
		float x, y, z;			//!< The position for the vertex.
		Ogre::RGBA diffuse;		//!< colour of the vertex
		float tu1, tv1;			//!< texture coordinates
	};

void CopyRenderer::fillRenderBuffer()
{
	float unit = 1.0f/16.0f;
	PCTVertex *buf = (PCTVertex *)mVBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
	
	float bgu1 = 11.0f*unit;
	float bgv1 = 13.0f*unit;
	float bgu2 = 12.0f*unit;
	float bgv2 = 14.0f*unit;
	
	float sunitx = 2.0f/80.0f;//16.0f/512;
	float sunity = 2.0f/25.0f;//24.0f/512;
	
	

	for (int i = 0; i < 25*80;i++)
	{
		DwarfFort::IconDesc desc;
		int row = i/25;
		int col = i%25;
		DwarfFort::Interface::getSingleton().fillIconDesc(desc,i); 
		
		if (desc.icon >= 0x100) desc.icon -=0x100;
		
		float fgu1 = unit/16.0f + unit * (float)(desc.icon & 0xF); 
		float fgv1 = unit/24.0f + unit * (float)((desc.icon & 0xF0) >> 4);
		
		float fgu2 = fgu1+unit -unit/16.0f; 
		float fgv2 = fgv1+unit -unit/24.0f;
		
		float sx = -1.0f + sunitx*(float)row;
		float sy = 1.0f - sunity*(float)col;

		buf->x = sx;
		buf->y = sy;
		buf->z = -0.1;
		buf->diffuse = desc.BGColor;
		buf->tu1 = bgu1;
		buf->tv1 = bgv1 ;
		buf++;
		
		buf->x = sx + sunitx;
		buf->y = sy - sunity;
		buf->z = -0.1;
		buf->diffuse = desc.BGColor;
		buf->tu1 = bgu2;
		buf->tv1 = bgv2;
		buf++;

		buf->x = sx;
		buf->y = sy - sunity;
		buf->z = -0.1;
		buf->diffuse = desc.BGColor;
		buf->tu1 = bgu1;
		buf->tv1 = bgv2;
		buf++;

		buf->x = sx;
		buf->y = sy;
		buf->z = -0.1;
		buf->diffuse = desc.BGColor;
		buf->tu1 = bgu1;
		buf->tv1 = bgv1 ;
		buf++;
		
		buf->x = sx + sunitx;
		buf->y = sy;
		buf->z = -0.1;
		buf->diffuse = desc.BGColor;
		buf->tu1 = bgu2;
		buf->tv1 = bgv1 ;
		buf++;

		buf->x = sx + sunitx;
		buf->y = sy - sunity;
		buf->z = -0.1;
		buf->diffuse = desc.BGColor;
		buf->tu1 = bgu2;
		buf->tv1 = bgv2;
		buf++;

		// foreground now
		buf->x = sx;
		buf->y = sy;
		buf->z = 0;
		buf->diffuse = desc.FGColor;
		buf->tu1 = fgu1;
		buf->tv1 = fgv1;
		buf++;
		
		buf->x = sx + sunitx;
		buf->y = sy - sunity;
		buf->z = 0;
		buf->diffuse = desc.FGColor;
		buf->tu1 = fgu2;
		buf->tv1 = fgv2;
		buf++;

		buf->x = sx;
		buf->y = sy - sunity;
		buf->z = 0;
		buf->diffuse = desc.FGColor;
		buf->tu1 = fgu1;
		buf->tv1 = fgv2;
		buf++;

		buf->x = sx;
		buf->y = sy;
		buf->z = 0;
		buf->diffuse = desc.FGColor;
		buf->tu1 = fgu1;
		buf->tv1 = fgv1;
		buf++;
		
		buf->x = sx + sunitx;
		buf->y = sy;
		buf->z = 0;
		buf->diffuse = desc.FGColor;
		buf->tu1 = fgu2;
		buf->tv1 = fgv1;
		buf++;

		buf->x = sx + sunitx;
		buf->y = sy - sunity;
		buf->z = 0;
		buf->diffuse = desc.FGColor;
		buf->tu1 = fgu2;
		buf->tv1 = fgv2;
		buf++;
	}
	mVBuffer->unlock();
}

void CopyRenderer::initRenderStates()
{
	if(!mRenderTex) 
	{
		
		Ogre::ResourcePtr ptr = Ogre::Root::getSingleton().getTextureManager()->getByName("DFScreen");
		mRenderTex = static_cast<Ogre::Texture *>(ptr.getPointer())->getBuffer()->getRenderTarget() ;
	}


	Ogre::LayerBlendModeEx colourBlendMode,alphaBlendMode;
	Ogre::TextureUnitState::UVWAddressingMode uvwAddressMode;

	colourBlendMode.blendType	= Ogre::LBT_COLOUR;
	colourBlendMode.source1	= Ogre::LBS_TEXTURE;
	colourBlendMode.source2	= Ogre::LBS_DIFFUSE;
	colourBlendMode.operation	= Ogre::LBX_MODULATE;

	alphaBlendMode.blendType	= Ogre::LBT_ALPHA;
	alphaBlendMode.source1	= Ogre::LBS_TEXTURE;
	alphaBlendMode.source2	= Ogre::LBS_DIFFUSE;
	alphaBlendMode.operation	= Ogre::LBX_MODULATE;

	uvwAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP;
	uvwAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP;
	uvwAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP;

	using namespace Ogre;

	Ogre::RenderSystem *renderSys = Root::getSingleton().getRenderSystem();
	// set-up matrices
	
	renderSys->_setWorldMatrix(Matrix4::IDENTITY);
	renderSys->_setViewMatrix(Matrix4::IDENTITY);
	renderSys->_setProjectionMatrix(Matrix4::IDENTITY);

	// initialise render settings
	renderSys->setLightingEnabled(false);
	renderSys->_setDepthBufferParams(false, false);
	renderSys->_setDepthBias(0, 0);
	renderSys->_setCullingMode(CULL_NONE);
	renderSys->_setFog(FOG_NONE);
	renderSys->_setColourBufferWriteEnabled(true, true, true, true);
	renderSys->unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
	renderSys->unbindGpuProgram(GPT_VERTEX_PROGRAM);
	renderSys->setShadingType(SO_GOURAUD);
	renderSys->_setPolygonMode(PM_SOLID);
	renderSys->_setTextureLayerAnisotropy(0,0);
	renderSys->_setTextureUnitFiltering(0,FO_NONE,FO_NONE,FO_NONE);
	// initialise texture settings
	renderSys->_setTextureCoordCalculation(0, TEXCALC_NONE);
	renderSys->_setTextureCoordSet(0, 0);
//	renderSys->_setTextureUnitFiltering(0, FO_LINEAR, FO_LINEAR, FO_POINT);
	renderSys->_setTextureAddressingMode(0, uvwAddressMode);
	renderSys->_setTextureMatrix(0, Matrix4::IDENTITY);
	renderSys->_setAlphaRejectSettings(CMPF_ALWAYS_PASS, 0,false);
	renderSys->_setTextureBlendMode(0, colourBlendMode);
	renderSys->_setTextureBlendMode(0, alphaBlendMode);
	renderSys->_disableTextureUnitsFrom(1);

	// enable alpha blending
	renderSys->_setSceneBlending(SBF_SOURCE_ALPHA, SBF_ONE_MINUS_SOURCE_ALPHA);
	renderSys->_setTexture(0,true,Ogre::String("DwarfCurses.png"));	
//	renderSys->detachRenderTarget(mRenderWindow->getName());
//	renderSys->attachRenderTarget(*mRenderTex);
}



